#include <iostream>
#include <functional>
#include <memory>

class Date
{
public:
    Date(int year = 2025, int month = 1, int day = 1)
        : _year(year), _month(month), _day(day)
    {
    }
    ~Date() { std::cout << "~Date()" << std::endl;}

    // 比较大小
    bool operator<(const Date &d) const
    {
        //*this < d
        if (_year < d._year)
            return true;
        else if (_year == d._year)
        {
            if (_month < d._month)
                return true;
            else if (_month == d._month)
            {
                if (_day < d._day)
                    return true;
            }
        }
        return false;
    }

private:
    int _year;
    int _month;
    int _day;
};

namespace zjx
{
    template <class T>
    class shared_ptr
    {
    public:
        // 构造，指向资源
        shared_ptr(T *ptr = nullptr): _ptr(ptr), _pcount(new int(1)){}

        // 构造时传入删除器
        template <class D>
        shared_ptr(T *ptr, D del)
            : _ptr(ptr), _pcount(new int(1)), _del(del)
        {}

        // 拷贝构造，指向资源，引用计数++
        shared_ptr(const shared_ptr<T> &sp)
            : _ptr(sp._ptr), _pcount(sp._pcount)
        {
            (*_pcount)++;
        }

        void release()
        {
            if (--(*_pcount) == 0)
            {
                // delete _ptr;
                _del(_ptr); // 删除器
                delete _pcount;
            }
        }
        // 赋值重载
        shared_ptr<T> &operator=(const shared_ptr<T> &sp)
        {
            // 不可以自己给自己赋值,指向的资源要不一样
            if (_ptr != sp._ptr)
            {
                release();// 现将原来指向的资源处理
                // 指向新资源
                _ptr = sp._ptr;
                _pcount = sp._pcount;
                ++(*_pcount);
            }
            return *this;
        }
        // 析构，释放资源
        ~shared_ptr(){release();}

        // 为了释放资源的时候new 开辟的就是使用delete , new[] 开辟的就使用 delete[]
        // 虽然shared_ptr 本身提供了特化版本，但是对于malloc 就又没用了
        // 所以另外一种解决方法：删除器
        // 定制删除器本质上为一个可调用对象, 函数指针、仿函数、lambda
        // 像指针一样使用智能指针
        T &operator*(){ return *_ptr; }
        T *operator->() { return _ptr; }
        // 提供两个get接口
        int use_count() const{ return *_pcount; }
        T *get() const{return _ptr;}

    private:
        T *_ptr;
        int *_pcount; // 不能使用静态成员变量，需要在堆上开辟空间
        std::function<void(T*)> _del = [](T *ptr){ delete ptr; }; // 缺省
    };
}

//函数模版 - 特化
template<class T>
void DeleteArrayFunc(T* ptr)
{
    delete[] ptr;
}

//仿函数
template<class T>
class DeleteArray
{
public:
    void operator()(T* ptr)
    {
        delete[] ptr;
    }
};

int main()
{
    //函数指针
    zjx::shared_ptr<Date> sp1(new Date[5] ,DeleteArrayFunc<Date>);
    //仿函数
    zjx::shared_ptr<Date> sp2(new Date[5] ,DeleteArray<Date>());
    //lambda
    auto deleteArrOBJ = [](Date* ptr){delete[] ptr;};
    zjx::shared_ptr<Date> sp3(new Date[5] ,deleteArrOBJ);
    return 0;
}